본문으로 건너뛰기

useMemo

🧑🏻‍💻 useMemo


useMemo 는 리렌더링 사이의 계산 결과를 캐시 (memoization)할 수 있는 React 훅이다.

✅ useMemo 문법

const cachedValue = useMemo(calculateValue, dependencies)
  • calculateValue는 캐시하려는 값을 계산하는 함수이다. React는 초기 렌더링 중에 인자없이 함수를 호출하고 그 결과를 반환하고 캐시한다. 이후 의존성이 변경되면 calculateValue를 다시 호출하여 새로운 값을 캐시한다.
  • dependenciescalculateValue 코드 내에서 참조되는 모든 반응형 값들의 목록이다.

🧑🏻‍💻 알고 가기


✅ useMemo를 왜 사용할까?

  • useMemo는 계산이 많거나 무거운 함수의 반환 ‘값’을 기억하도록 도와준다. 이를 통해 동일한 계산을 반복하지 않고, 필요한 캐시된 값을 사용하여 불필요한 연산을 줄일 수 있어서 성능을 향상 시킬 수 있다. 이런 종류의 캐시를 memorization 이라고 한다.

✅ useMemo언제 사용해야 하는가?

  • 계산이 눈에 띄게 느리면서 의존성이 거의 변하지 않는 경우에 사용하자.
  • useMemo는 성능 최적화를 위해서만 사용해야한다. 그렇지 않다면 State Hooks 또는 Ref Hooks가 더 적절할 수 있다.
  • 인터렉션이 많이 일어나지 않는 앱의 경우 일반적으로 필요하지 않다.

✅ useMemoReact.memo 의 차이점은?

  • useMemo는 ‘값’을 메모이제이션하여 리렌더링을 최적화하기 위해 사용된다.
  • React.memo는 ‘함수 컴포넌트’를 메모이제이션하여 렌더링을 최적화하기 위해 사용된다.

✅ 주의 사항

  • 루프 안에서 useMemo를 호출할 수 없다.
  • 어떤 useMemo가 다른 useMemo의 의존성으로 들어간다면, 두 로직을 통합하여 사용하는 것이 좋다.

🧑🏻‍💻 활용 및 생각할 거리


✅ React가 캐시된 값을 폐기하는 경우는 언제일까?

  1. React는 개발 중에 컴포넌트 파일을 수정하면 캐시된 값을 폐기한다.
  2. 개발 환경 및 상용 환경 모두에서, 초기 마운트 중에 컴포넌트가 일시 중단(suspend)되면 React는 캐시를 폐기한다.
  • React는 이외 특별한 이유가 있지 않는 한 캐시된 값을 유지하려고 한다.

✅ 비용이 많이 드는 계산인지 아닌지 판단하는 방법

  1. 코드에 소요된 시간을 측정한다.

    console.time('filter array');
    const visibleTodos = filterTodos(todos, tab);
    console.timeEnd('filter array');

    → 소요된 시간이 길 때 (예: 1ms 이상) 해당 계산을 메모해 두는 것이 좋다.

  2. useMemo로 감싼 후 다시 소요 시간을 측정해 본다.

    console.time('filter array');
    const visibleTodos = useMemo(() => {
    return filterTodos(todos, tab);
    }, [todos, tab]);
    console.timeEnd('filter array');

    → 이때 useMemo는 첫 번째 렌더링을 빠르게 만들지는 않는다. 업데이트 시 최적화에만 도움이 된다.

⚠️ 참고 사항

  • 개발 중에 성능을 측정하는 것은 반드시 정확한 결과를 제공하지는 않는다. → 가장 정확한 시간 측정을 위해서는 상용 앱을 빌드하고 사용자가 사용하는 것과 동일한 기기에서 테스트하자.
  • 개발자의 컴퓨터가 유저의 컴퓨터보다 빠를 수 있기 때문에 인위적으로 속도를 늦춰 성능을 테스트하자. → Chrome은 이를 위한 CPU 쓰로틀링 옵션을 제공한다. → 또한 React 개발자 도구 profiler를 사용하여 메모화가 필요한 컴포넌트를 판단할 수 있다.

✅ 함수를 캐시하고 싶다면?

// useMemo
export default function Page({ productId, referrer }) {
const handleSubmit = useMemo(() => {
return (orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails
});
};
}, [productId, referrer]);

return <Form onSubmit={handleSubmit} />;
}

// useCallback
export default function Page({ productId, referrer }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails
});
}, [productId, referrer]);

return <Form onSubmit={handleSubmit} />;
}
  • useMemo 를 사용하면 중첩 함수를 추가로 작성하게 된다. 이럴 필요 없이 함수를 캐시할 때는 useMemo 대신 useCallback으로 감싸자. 그 외 다른 이점은 useMemo와 동일하다.